#include "Socket.h"

using namespace std;

Socket::Socket() {
	if((fd = socket(AF_INET,SOCK_STREAM,0))==-1)
		valido=false;
	else
		valido=true;
	bufferAux="";
}

//Constructor por copia Privado
Socket::Socket(int Fd)
{
  	valido=true;
   	fd=Fd;
}

//-----------------Para el Servidor-----------------------------//
int Socket::bind(int puerto)
{
	if(!is_valid())
		return -1;
	else{
		struct sockaddr_in serv_addr;
		memset((char*)&serv_addr,0,sizeof(serv_addr));
		serv_addr.sin_family=AF_INET;
		serv_addr.sin_port=htons(puerto);
		serv_addr.sin_addr.s_addr=INADDR_ANY;
		cerr<<"Bindeando Socket al puerto "<<puerto<<"..."<<endl;
		return (::bind(this->fd,(struct sockaddr*)&serv_addr, sizeof(serv_addr)));
	}
}


int Socket:: listen()
{
	if(!is_valid())
		return -1;
	else{
		cerr<<"Listening..."<<endl;
		return (::listen(fd, BACKLOG));
	}
}


Socket *Socket::accept()
{
	struct sockaddr_in cli_addr;
	::socklen_t addr_size;
	addr_size= sizeof(cli_addr);
   	int new_fd= ::accept(fd,(struct sockaddr*)& cli_addr, &addr_size );
   	if((new_fd) != -1){
		cerr<<"Socket accepted..."<<endl;
		return new Socket(new_fd);
	}
	else
   		return NULL;
}


//-----------------Para el Cliente-----------------------------//
int Socket::connect(const char*  host, int  port)
{
	if(!is_valid())
		return -1;
	struct hostent *he;
	if((he=gethostbyname(host))==NULL){
		close();
		return -1;
	}
	else{
		struct sockaddr_in serv_addr;
		memset((char*)&serv_addr,0,sizeof(serv_addr));
		serv_addr.sin_family =AF_INET;
		serv_addr.sin_port=htons(port);
		serv_addr.sin_addr=*((struct in_addr*) he->h_addr);
		cerr<<"Conectando cliente al server: "<<host<<":"<<port<<"..."<<endl;
		return(::connect(fd,(struct sockaddr*)&serv_addr,sizeof(struct sockaddr)));
	}
}


//-----------------Para Cliente y Servidor-----------------------//
int Socket::send(char* msj, int len){
	return(::send(fd, msj, len, 0));
}



int Socket::recvtimeout(std::string& stream)
{
    fd_set fds;
    int n;
    struct timeval tv;

    // Construir el conjunto de descriptores de fichero
    FD_ZERO(&fds);
    FD_SET(fd, &fds);

    // Construir la estructura timeval del temporizador
    tv.tv_sec = TIMEOUT;
    tv.tv_usec = 0;

    // Esperar hasta que se reciban datos o venza el temporizador
    n = select(fd+1, &fds, NULL, NULL, &tv);
    if (n == 0) return -2; // ¡El temporizador ha vencido!
    if (n == -1) return -1; // error

    // Los datos deben estar ahí, así que llamo normalmente a recv()
    return recive(stream);
}


int Socket::recive(std::string& stream_externo){

	this->bufferAux.clear();

	bool terminado=false;	
	int len=MAXDATATRANS, bytes;
	unsigned int pos;
	char buff[MAXDATATRANS]; 
	string stream, streamAux;
	//Si el buffer habia guardado algo previamente, lo cargo ahora
	if(this->bufferAux!=""){
		stream=bufferAux;
		this->bufferAux="";	
	}
	while(!terminado){
		bytes=::recv(fd,buff,len,0);


		if(bytes<=0){
			stream_externo="ERROR_INTERNO_RECIVE";
			return -1;
		}
		streamAux+=buff;
		pos=streamAux.find("</env:Envelope>", 0 );

		if((pos)!=string::npos){
		terminado=true;
		stream+=streamAux.substr( 0, pos+ 16);
		}
	}
	//Si lei mas bytes luego del /n debo guardarlos pues es parte del 
	//	proximo mensaje.

	if((bytes-1) > (signed)(streamAux.substr( 0, pos )).length() )
		this->bufferAux= streamAux.substr( pos,pos+bytes);


	stream_externo=stream;
	return bytes;
}

int Socket::shutdown(int how){
	return(::shutdown(fd,how));
}


int Socket::close(){
	::close(fd);
	return 0;
}
